import { defineComponent, reactive, toRefs, computed, onMounted, onBeforeUnmount } from "vue"
import { inject } from "vue"

// import { COMPS_NAME } from './util/constant'
import VeIcon from "amtf/components/icon"

import { ICON_NAMES } from "amtf/constants"
import { INIT_DATA, EMIT_EVENTS, CONTEXTMENU_NODE_TYPES } from "./util/constant"
// import { debounce, cloneDeep } from 'lodash'
import { useDebounceFn } from "@vueuse/core"
import * as util from 'amtf/utils';

import { eventsOutside } from "amtf/directives"

import { useEmitter } from "amtf/hooks"
import emitter from "amtf/utils/emitter"
import { use样式 } from "amtf/hooks"
import {
    getViewportOffset,
    getMousePosition,
    getValByUnit,
    拼组件名,
    isFunction,
    isBoolean,
    getRandomId,
} from "amtf/utils"
const 主名 = "contextmenu"
const 组件名 = 拼组件名(主名)
import {是浏览器环境否} from 'amtf/utils';

export default defineComponent({
    name: 组件名,
    directives: {
        "events-outside": eventsOutside,
    },
    props: {
        options: {
            type: Array,
            required: true,
        },
        eventTarget: {
           type: [String, 是浏览器环境否 ? HTMLElement : Object],
            required: true,
        },
    },
    setup(props) {
        const { dispatch } = useEmitter(inject("表格id"))
        const { 拼样式名_提前传主名 } = use样式(主名)

        const state = reactive({
            internalOptions: [],
            panelOptions: [],
            eventTargetEl: "",
            rootContextmenuId: "",
            isChildrenPanelsClicked: false,
            isPanelRightDirection: true,
            isPanelsEmptyed: true,
        })

        const activeMenuIds = computed(() => {
            return state.panelOptions.map(x => x.parentId)
        })

        function getRandomIdWithPrefix() {
            return 拼样式名_提前传主名(getRandomId())
        }

        function hasChildren(option) {
            return Array.isArray(option.children) && option.children.length
        }

        function getPanelOptionByMenuId(options, menuId) {
            for (let i = 0; i < options.length; i++) {
                if (options[i].id === menuId) {
                    return options[i].children
                }
                if (options[i].children) {
                    const panelOption = getPanelOptionByMenuId(options[i].children, menuId)
                    if (panelOption) return panelOption
                }
            }
        }

        function getParentContextmenuPanelEl(contextmenuPanelId) {
            let result
            const { panelOptions } = state
            const panelIndex = panelOptions.findIndex(x => x.parentId === contextmenuPanelId)
            if (panelIndex > 0) {
                const parentPanelId = panelOptions[panelIndex - 1].parentId
                result = document.querySelector(`#${parentPanelId}`)
            }
            return result
        }

        function createPanelByHover({ event, menu }) {
            const { internalOptions, panelOptions } = state
            if (state.isPanelsEmptyed) return false
            if (panelOptions.findIndex(x => x.parentId === menu.id) > -1) return false
            const deletePanelDeeps = panelOptions
                .filter(x => x.parentDeep >= menu.deep)
                .map(x => x.parentDeep)
                .reverse()
            if (deletePanelDeeps.length) {
                for (let i = deletePanelDeeps.length - 1; i >= 0; i--) {
                    const delIndex = panelOptions.findIndex(x => x.parentDeep === deletePanelDeeps[i])
                    if (delIndex > -1) {
                        state.panelOptions.splice(delIndex, 1)
                    }
                }
            }
            const panelOption = getPanelOptionByMenuId(internalOptions, menu.id)
            if (panelOption) {
                createPanelOptions({ options: panelOption, currentMenu: menu })
                onMounted(() => {
                    addContextmenuPanelToBody({ contextmenuId: menu.id })
                    showContextmenuPanel({ event, contextmenuId: menu.id })
                })
            }
        }

        function createPanelOptions({ options, currentMenu }) {
            if (Array.isArray(options)) {
                let menus = options.map(option => {
                    return {
                        hasChildren: hasChildren(option),
                        ...option,
                    }
                })
                state.panelOptions.push({
                    parentId: currentMenu ? currentMenu.id : state.rootContextmenuId,
                    parentDeep: currentMenu ? currentMenu.deep : INIT_DATA.PARENT_DEEP,
                    menus: menus,
                })
            }
        }

        function createInternalOptionsRecursion(options, deep = 0) {
            options.id = getRandomIdWithPrefix()
            options.deep = deep
            deep++
            if (Array.isArray(options.children)) {
                options.children.map(option => {
                    return createInternalOptionsRecursion(option, deep)
                })
            }
            return options
        }

        function createInternalOptions() {
            state.internalOptions = util.深拷贝(props.options).map(option => {
            // state.internalOptions = cloneDeep(props.options).map(option => {
                return createInternalOptionsRecursion(option)
            })
        }

        function showRootContextmenuPanel(event) {
            event.preventDefault()
            const { rootContextmenuId } = state
            if (rootContextmenuId) {
                resetContextmenu()
                showContextmenuPanel({
                    event,
                    contextmenuId: rootContextmenuId,
                    isRootContextmenu: true,
                })
                state.isPanelsEmptyed = false
            }
        }

        function showContextmenuPanel({ event, contextmenuId, isRootContextmenu }) {
            let contextmenuPanelEl = document.querySelector(`#${contextmenuId}`)
            if (contextmenuPanelEl) {
                contextmenuPanelEl.innerHTML = ""
                contextmenuPanelEl.appendChild(state.$refs[contextmenuId])
                contextmenuPanelEl.style.position = "absolute"
                contextmenuPanelEl.classList.add(拼样式名_提前传主名("popper"))
                const { width: currentPanelWidth, height: currentPanelHeight } =
                    contextmenuPanelEl.getBoundingClientRect()
                if (isRootContextmenu) {
                    const {
                        left: clickLeft,
                        top: clickTop,
                        right: clickRight,
                        bottom: clickBottom,
                    } = getMousePosition(event)
                    let panelX = 0
                    let panelY = 0
                    if (clickRight >= currentPanelWidth) {
                        panelX = clickLeft
                        state.isPanelRightDirection = true
                    } else {
                        panelX = clickLeft - currentPanelWidth
                        state.isPanelRightDirection = false
                    }
                    if (clickBottom >= currentPanelHeight) {
                        panelY = clickTop
                    } else {
                        panelY = clickTop - currentPanelHeight
                    }
                    contextmenuPanelEl.style.left = panelX + "px"
                    contextmenuPanelEl.style.top = panelY + "px"
                } else {
                    const parentContextmenuPanelEl = getParentContextmenuPanelEl(contextmenuId)
                    if (parentContextmenuPanelEl) {
                        const { left: parentPanelLeft, right: parentPanelRight } =
                            getViewportOffset(parentContextmenuPanelEl)
                        const { top: clickTop, bottom: clickBottom } = getMousePosition(event)
                        const { width: parentPanelWidth } = parentContextmenuPanelEl.getBoundingClientRect()
                        let panelX = 0
                        let panelY = 0
                        if (state.isPanelRightDirection) {
                            if (parentPanelRight >= currentPanelWidth) {
                                panelX = parentPanelLeft + parentPanelWidth
                            } else {
                                panelX = parentPanelLeft - parentPanelWidth
                            }
                        } else {
                            if (parentPanelLeft >= currentPanelWidth) {
                                panelX = parentPanelLeft - parentPanelWidth
                            } else {
                                panelX = parentPanelLeft + parentPanelWidth
                            }
                        }
                        if (clickBottom >= currentPanelHeight) {
                            panelY = clickTop
                        } else {
                            panelY = clickTop - currentPanelHeight
                        }
                        contextmenuPanelEl.style.left = panelX + "px"
                        contextmenuPanelEl.style.top = panelY + "px"
                    }
                }
            }
        }

        function emptyContextmenuPanels() {
            setTimeout(() => {
                if (state.isChildrenPanelsClicked) {
                    state.isChildrenPanelsClicked = false
                } else {
                    removeOrEmptyPanels()
                    state.isPanelsEmptyed = true
                }
            })
        }

        function removeOrEmptyPanels(isRemove = false) {
            const { panelOptions } = state
            panelOptions.forEach(panelOption => {
                let contextmenuPanelEl = document.querySelector(`#${panelOption.parentId}`)
                if (contextmenuPanelEl) {
                    if (isRemove) {
                        contextmenuPanelEl.remove()
                    } else {
                        contextmenuPanelEl.innerHTML = ""
                    }
                }
            })
        }

        function resetContextmenu() {
            state.panelOptions = []
            createPanelOptions({ options: state.internalOptions })
        }

        function addContextmenuPanelToBody({ contextmenuId }) {
            let contextmenuPanelEl = document.querySelector(`#${contextmenuId}`)
            if (contextmenuPanelEl) {
                return false
            } else {
                let containerEl = document.createElement("div")
                containerEl.setAttribute("id", contextmenuId)
                document.body.appendChild(containerEl)
            }
        }

        function addRootContextmenuPanelToBody() {
            if (state.rootContextmenuId) {
                addContextmenuPanelToBody({ contextmenuId: state.rootContextmenuId })
            }
        }

        function registerContextmenuEvent() {
            if (typeof props.eventTarget === "string" && props.eventTarget.length > 0) {
                state.eventTargetEl = document.querySelector(props.eventTarget)
            } else {
                state.eventTargetEl = props.eventTarget
            }
            if (state.eventTargetEl) {
                state.eventTargetEl.addEventListener("contextmenu", showRootContextmenuPanel)
            }
        }

        function removeContextmenuEvent() {
            if (state.eventTargetEl) {
                state.eventTargetEl.removeEventListener("contextmenu", showRootContextmenuPanel)
            }
        }

        function hideContextmenu() {
            emptyContextmenuPanels()
        }

        onMounted(() => {
            addRootContextmenuPanelToBody()
        })

        onBeforeUnmount(() => {
            removeContextmenuEvent()
            removeOrEmptyPanels(true)
        })

        // const debounceCreatePanelByHover = debounce(createPanelByHover, 300)
        // const { run: debounceCreatePanelByHover } = useDebounceFn(createPanelByHover, 300);
        const debounceCreatePanelByHover = useDebounceFn(createPanelByHover, 300)
        if (Array.isArray(props.options) && props.options.length > 0) {
            state.rootContextmenuId = getRandomIdWithPrefix()
            createInternalOptions()
            createPanelOptions({ options: state.internalOptions })
            resetContextmenu()
            addRootContextmenuPanelToBody()
        }
        if (props.eventTarget) {
            registerContextmenuEvent()
        }

        return () => (
            <div class={["ve-contextmenu"]} style={{ display: "none" }}>
                {state.panelOptions.map((panelOption, panelIndex) => (
                    <div
                        ref={panelOption.parentId}
                        class={拼样式名_提前传主名("panel")}
                        directives={[
                            {
                                name: "events-outside",
                                value: {
                                    events: ["click"],
                                    callback: e => (panelIndex === 0 ? emptyContextmenuPanels() : null),
                                },
                            },
                        ]}
                        onClick={() => (panelIndex !== 0 ? (state.isChildrenPanelsClicked = true) : null)}
                        onContextmenu={e => e.preventDefault()}>
                        <ul class={拼样式名_提前传主名("list")}>
                            {panelOption.menus.map(menu => {
                                let contextmenuNodeProps
                                if (menu.type !== CONTEXTMENU_NODE_TYPES.SEPARATOR) {
                                    contextmenuNodeProps = {
                                        class: {
                                            [拼样式名_提前传主名("node")]: true,
                                            [拼样式名_提前传主名("node-active")]: activeMenuIds.includes(menu.id),
                                            [拼样式名_提前传主名("node-disabled")]: menu.disabled,
                                        },
                                        onMouseover: event => {
                                            if (!menu.disabled) {
                                                debounceCreatePanelByHover({ event, menu })
                                            }
                                        },
                                        onClick: () => {
                                            if (!menu.disabled && !hasChildren(menu)) {
                                                emit(EMIT_EVENTS.ON_NODE_CLICK, menu.type)
                                                setTimeout(() => {
                                                    emptyContextmenuPanels()
                                                }, 50)
                                            }
                                        },
                                    }
                                } else {
                                    contextmenuNodeProps = {
                                        class: {
                                            [拼样式名_提前传主名("node-separator")]: true,
                                        },
                                    }
                                }
                                if (menu.type !== CONTEXTMENU_NODE_TYPES.SEPARATOR) {
                                    return (
                                        <li {...contextmenuNodeProps}>
                                            <span class={拼样式名_提前传主名("node-label")}>{menu.label}</span>
                                            {menu.hasChildren && (
                                                <VeIcon
                                                    class={拼样式名_提前传主名("node-icon-postfix")}
                                                    name={ICON_NAMES.RIGHT_ARROW}
                                                />
                                            )}
                                        </li>
                                    )
                                } else {
                                    return <li {...contextmenuNodeProps}></li>
                                }
                            })}
                        </ul>
                    </div>
                ))}
            </div>
        )
    },
})
